#ifndef __M_COMMON_H__
#define __M_COMMON_H__

#include <iostream>
#include <string>
#include "EventUnit.hpp"
#include "InetAddr.hpp"
#include "Reactor.hpp"

#include <fcntl.h>

void SetNonBlock(int fd)
{
    int f1 = fcntl(fd, F_GETFL);
    if(f1 < 0)
    {
        return;
    }
    fcntl(fd, F_SETFL, f1 | O_NONBLOCK);
}

int recver(EventUnit* evut) {
    // 循环读取
    int sockfd = evut->_sockfd;
    bool isWrong = false;
    while(1) {
        char buffer[1024];
        ssize_t size = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if(size < 0) {
            // 数据被读取完
            if(errno == EAGAIN || errno == EWOULDBLOCK) {
                break;
            }
            // 被信号中断，继续读
            else if(errno == EINTR) {
                continue;
            }
            // 读取出错
            else {
                isWrong = true;
                break;
            }
        }

        buffer[size] = 0;
        evut->_inbuffer += buffer;
    }

    // 需要进行异常判断
    if(isWrong) {
        evut->_error(evut);
        return -1;
    }

    // 代码走到这，已经把套接字的数据读取完毕，需要解决tcp传输的粘包问题
    // 自定义报文：反序列化获取数据，业务处理（抛入线程池），得到结果构建应答加入发送缓冲区
    // 这里省略这些步骤

    std::string s = "Reactor have received: ";
    evut->_outbuffer += s + evut->_inbuffer;
    // 这里是关键，打开写epoll写事件的监控，reactor的事件分配器的事件监控可以立刻响应
    // 因为写事件默认就绪
    evut->_R->EnableReadWrite(sockfd, true, true);

    return 0;
}

int sender(EventUnit* evut) {
    // 累计已发送的字节数
    int sockfd = evut->_sockfd;
    size_t total = 0;
    std::string& out = evut->_outbuffer;
    bool isWrong = false, isFull = false;
    while(1) {
        // send不是说你想发送多少就多少，size是你实际发送的字节，要循环发送
        ssize_t size = send(sockfd, out.c_str() + total, out.size() - total, 0);
        if(size < 0) {
            // 底层的发送缓冲区写满
            if(errno == EAGAIN || errno == EWOULDBLOCK) {
                // 已经发送的移出缓冲区
                out.erase(0, total);
                isFull = true;
                break;
            }
            // 被信号中断，继续发
            else if(errno == EINTR) {
                continue;
            }
            // 发送出错
            else {
                isWrong = true;
                break;
            }
        }
        
        total += size;
        if(total >= out.size()) {
            out.clear();
        }
    }

    if(isWrong) {
        evut->_error(evut);
        return -1;
    }

    // 如果底层发送缓冲区满了，需要继续关注写事件
    bool isWrite = isFull ? true : false;

    evut->_R->EnableReadWrite(sockfd, true, isWrite);
    return 0;
}

int errorer(EventUnit* evut) {
    // 直接关闭连接
    int sockfd = evut->_sockfd;
    evut->_R->DelEvent(sockfd);
    close(sockfd);
    std::cerr << "close sockfd!" << std::endl;
    return 0;
}


int accepter(EventUnit* evut) {
    while(1) {
        InetAddr addr;
        socklen_t len = addr.NetAddrLen();
        int sockfd = accept(evut->_sockfd, addr.netAddrPtr(), &len);
        if(sockfd < 0) {
            // 不一定是失败
            // 连接读取完
            if(errno == EAGAIN || errno == EWOULDBLOCK) {
                return 0;
            }
            // 被信号中断
            else if(errno == EINTR) {
                continue;
            }
            // 真正的出错
            else {
                std::cerr << "accept error!" << std::endl;
                return -1;
            }
        }

        // 对文件描述符设置非阻塞i模式
        SetNonBlock(sockfd);
        EventUnit sock_evut;
        sock_evut._sockfd = sockfd;
        sock_evut._R = evut->_R;
        sock_evut.RegisterCallback(recver, sender, errorer);

        Reactor* R = evut->_R;
        R->AddEvent(sockfd, EPOLLIN | EPOLLET, sock_evut);
        return 0;
    }
}



#endif